//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved

#include "pch.h"
#include "Trace.h"

DWORD g_dwLogLevel = TRACE_LEVEL_NORMAL;

void Trace(DWORD dwLevel, LPCWSTR pszFormat, ...)
{
	if (g_dwLogLevel > dwLevel)
	{
		return;
	}
	WCHAR szTextBuf[256];
	va_list args;
	va_start(args, pszFormat);

	StringCchVPrintf(szTextBuf, _countof(szTextBuf), pszFormat, args);

	OutputDebugString(szTextBuf);
}

void TraceError(LPCSTR pszFile, long nLine, LPCSTR pszFunc, Object ^pThis, HRESULT hr)
{
	TraceError(pszFile, nLine, pszFunc, reinterpret_cast<IInspectable*>(pThis), hr);
}

void TraceError(LPCSTR pszFile, long nLine, LPCSTR pszFunc, const void * pThis, HRESULT hr)
{
	if (SUCCEEDED(hr))
	{
		return;
	}
	LPCSTR psz = pszFile + strlen(pszFile);
	for (; psz > pszFile; psz--)
	{
		if (*psz == '\\')
		{
			pszFile = psz + 1;
			break;
		}
	}
	WCHAR szTextBuf[256];
	szTextBuf[0] = 0;
	StringCchPrintf(szTextBuf, _countof(szTextBuf), L"%S:%d (%S@%p) FAILED hr=%x\n", pszFile, nLine, pszFunc, pThis, hr);
	OutputDebugString(szTextBuf);
}

void PrintSampleInfo(IMFSample *pSample)
{
	ComPtr<IMFMediaBuffer> spBuffer;
	pSample->GetBufferByIndex(0, &spBuffer);

	DWORD cbTotalLen;
	DWORD cbMaxLen;
	DWORD cbCurLen;
	LONGLONG llDur;
	LONGLONG llTs;
	pSample->GetTotalLength(&cbTotalLen);
	pSample->GetSampleDuration(&llDur);
	pSample->GetSampleTime(&llTs);

	Trace(TRACE_LEVEL_HIGH, L"Sample - Ts: %I64d Dur: %I64d Len: %d\n", llTs, llDur, cbTotalLen);
	BYTE *pByte;
	spBuffer->Lock(&pByte, &cbMaxLen, &cbCurLen);
	if (cbCurLen >= sizeof(LONGLONG))
	{
		Trace(TRACE_LEVEL_HIGH, L"Sample beginning - Ts: 0x%I64x\n", *(LONGLONG*)pByte);
	}

	PrintAttributes(pSample);
}

void PrintAttributes(IMFAttributes *pAttributes)
{
	UINT32 cAttr;
	pAttributes->GetCount(&cAttr);
	Trace(TRACE_LEVEL_HIGH, L"No attributes %d\n", cAttr);

	for (UINT32 i = 0; i < cAttr; ++i)
	{
		const DWORD CHARS_IN_GUID = 39;
		PROPVARIANT var = { 0 };
		GUID gui;
		OLECHAR szAttrId[CHARS_IN_GUID];

		pAttributes->GetItemByIndex(i, &gui, &var);
		StringFromGUID2(gui, szAttrId, CHARS_IN_GUID);

		switch (var.vt)
		{
		case MF_ATTRIBUTE_UINT32:
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s - %d\n", szAttrId, var.uintVal);
			break;
		case MF_ATTRIBUTE_UINT64:
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s - %I64d\n", szAttrId, var.uhVal.QuadPart);
			break;
		case MF_ATTRIBUTE_DOUBLE:
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s - %f\n", szAttrId, var.dblVal);
			break;
		case MF_ATTRIBUTE_GUID:
			OLECHAR szAttrVal[CHARS_IN_GUID];
			StringFromGUID2(*var.puuid, szAttrVal, CHARS_IN_GUID);
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s - %s\n", szAttrId, szAttrVal);
			break;
		case MF_ATTRIBUTE_BLOB:
			if (var.caub.cElems >= 8)
			{
				Trace(TRACE_LEVEL_HIGH, L"Attr: %s BLOB - %I64x\n", szAttrId, *(LONGLONG*)var.caub.pElems);
			}
			else if (var.caub.cElems > 0)
			{
				Trace(TRACE_LEVEL_HIGH, L"Attr: %s BLOB - %c\n", szAttrId, var.caub.pElems[0]);
			}
			else
			{
				Trace(TRACE_LEVEL_HIGH, L"Attr: %s empty blob\n", szAttrId, var.caub.pElems[0]);
			}
			break;
		case MF_ATTRIBUTE_STRING:
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s %s\n", szAttrId, var.pwszVal);
			break;
		default:
			Trace(TRACE_LEVEL_HIGH, L"Attr: %s TYPE %hd\n", szAttrId, var.vt);
			break;
		}

		PropVariantClear(&var);
	}
}
